#include "biplTypes.h"
#include <boost/lexical_cast.hpp>

/// implicitly convert to bool
stringTypes::operator bool() const
{
	return !str.empty();
}

/// output stream operator
std::ostream&
	operator<<(std::ostream& out, const stringTypes& s)
{
	out << s.str;
	return out;
}

/// String Concatenation Operators
const stringTypes operator+(const stringTypes& lhs, const stringTypes& rhs)
{
	return stringTypes(lhs.str + rhs.str);
}

stringTypes& operator+=(stringTypes& lhs, const stringTypes& rhs)
{
	lhs.str += rhs.str;
	return lhs;
}

/// Equality Operators
boolTypes operator==(const stringTypes& left, const boolTypes& right)
{
	return boolTypes(left.toBoolean() == right);
}

boolTypes operator!=(const stringTypes& left, const boolTypes& right)
{
	return boolTypes(left.toBoolean() != right);
}

boolTypes operator==(const boolTypes& left, const stringTypes& right)
{
	return boolTypes(left == right.toBoolean());
}

boolTypes operator!=(const boolTypes& left, const stringTypes& right)
{
	return boolTypes(left != right.toBoolean());
}

boolTypes operator==(const stringTypes& left, const stringTypes& right)
{
	return boolTypes(left.str == right.str);
}

boolTypes operator!=(const stringTypes& left, const stringTypes& right)
{
	return boolTypes(left.str != right.str);
}

/// Logical Operators
boolTypes operator!(const stringTypes& s)
{
	return !s.toBoolean();
}

boolTypes operator&&(const stringTypes& left, const stringTypes& right)
{
	return left.toBoolean() && right.toBoolean();
}

boolTypes operator||(const stringTypes& left, const stringTypes& right)
{
	return left.toBoolean() || right.toBoolean();
}

/// Type conversion functions
boolTypes stringTypes::toBoolean() const
{
	if (str.empty()) {
		return boolTypes(false);
	} else {
		return boolTypes(true);	
	}
}

floatTypes stringTypes::toFloat() const
{
	float var;
	try {
        var = boost::lexical_cast<float>(str);
    } catch (boost::bad_lexical_cast&) {
		std::cout << "Warning: Converting String to Float fail. Return 0.0f" << std::endl;
        return floatTypes(0.0f);
    }
	return floatTypes(var);
}

degreeTypes stringTypes::toDegree() const
{
	char buf[2][40] = {NULL};
	float tmp;

	/// skip the case where the string is too long
	if (str.length() > 40 ) {
		std::cout << "Warning 0: Converting String to Degree fail. Return [0.0f]" << std::endl;
		return degreeTypes(0.0f);
	}
	/// separate the string fail
	if (sscanf_s(str.c_str(), "[ %[0-9efE.+-] %[]]",
							buf[0], _countof(buf[0]),
							buf[1], _countof(buf[1])) != 2) {
		//std::cout << buf[0] << " " << buf[1] << std::endl;
		std::cout << "Warning 1: Converting String to Degree fail. Return [0.0f]" << std::endl;
		return degreeTypes(0.0f);
	}
	if (strlen(buf[1]) != 1) {
		std::cout << "Warning 2: Converting String to Degree fail. Return [0.0f]" << std::endl;
		return degreeTypes(0.0f);
	}
	try {
		tmp = boost::lexical_cast<float>(buf[0]);
	} catch (boost::bad_lexical_cast&) {
		std::cout << "Warning 3: Converting String to Degree fail. Return [0.0f]" << std::endl;
		return degreeTypes(0.0f);
	}
	return degreeTypes(tmp);
}

pairTypes stringTypes::toPair() const
{
	char buf[3][40] = {NULL};
	float f1, f2;

	/// skip the case where the string is too long
	if (str.length() > 40 ) {
		std::cout << "Warning 0: Converting String to Float fail. Return [0.0f, 0.0f]" << std::endl;
		return pairTypes(0.0f, 0.0f);
	}
	/// separate the string fail
	if (sscanf_s(str.c_str(), "[ %[0-9efE.+-], %[0-9efE.+-] %[]]",
							buf[0], _countof(buf[0]), 
							buf[1], _countof(buf[1]),
							buf[2], _countof(buf[2])) != 3) {
		//std::cout << buf[0] << " " << buf[1] << std::endl;
		std::cout << "Warning 1: Converting String to Pair fail. Return [0.0f, 0.0f]" << std::endl;
		return pairTypes(0.0f, 0.0f);
	}
	if (strlen(buf[2]) != 1) {
		std::cout << "Warning 2: Converting String to Pair fail. Return [0.0f, 0.0f]" << std::endl;
		return pairTypes(0.0f, 0.0f);
	}
	try {
		f1 = boost::lexical_cast<float>(buf[0]);
		f2 = boost::lexical_cast<float>(buf[1]);
	} catch (boost::bad_lexical_cast&) {
		std::cout << "Warning 3: Converting String to Pair fail. Return [0.0f, 0.0f]" << std::endl;
		return pairTypes(0.0f, 0.0f);
	}
	return pairTypes(f1, f2);
}

intTypes stringTypes::toInteger() const
{
	int var;
	try {
        var = boost::lexical_cast<int>(str);
    } catch (boost::bad_lexical_cast&) {
		std::cout << "Warning: Converting String to Int fail. Return 0." << std::endl;
        return intTypes(0);
    }
	return intTypes(var);
}

stringTypes stringTypes::toString() const
{	
	return stringTypes(str);
}